package org.example;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import org.example.bean.BoundingBox;
import org.example.bean.BufferedImageBuilder;
import org.example.bean.Content;
import org.example.bean.GeoPoint;
import org.example.util.FourBoundariesGraphUtil;
import org.example.util.GPSUtil;
import org.example.util.HttpOkUtil;
import org.example.util.LatLngUtil;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

public class SiZiApp {

    public static void main(String[] args) {
        makeSiZiTu();
    }

    public static void makeSiZiTu() {
//        yzp测试地块8 127亩 长条形
//        String path = "[[31.371952,121.260622],[31.372069,121.272857],[31.371363,121.272765],[31.371343,121.260645],[31.371952,121.260622]]";
//        yzp测试地块7 900亩
//        String path = "[[31.348579,121.237993],[31.348286,121.260824],[31.343595,121.2325],[31.348579,121.237993]]";
//        yzp测试地块6 1w亩
//        String path = "[[31.349848,121.231852],[31.349082,121.274591],[31.329681,121.254865],[31.34168,121.216609],[31.349848,121.231852]]";
//        String path = "[[31.341333,121.226297],[31.337222,121.222361],[31.3345,121.229712],[31.340222,121.232379],[31.343167,121.231078],[31.3395,121.229126],[31.341333,121.226297]]";
//       yzp测试地块3 3000亩
//        String path = "[[31.359471,121.188647],[31.361108,121.193806],[31.359649,121.207331],[31.352743,121.208028],[31.350689,121.197954],[31.351553,121.185161],[31.358994,121.182477],[31.359471,121.188647]]";
//       yzp测试地块2 0.94亩
        String path = "[[31.21729,121.583274],[31.217096,121.58378],[31.216985,121.583457],[31.21729,121.583274]]";
//         yzp测试地块  13.17亩
//        String path = "[[31.221444,121.582566],[31.221275,121.583318],[31.221464,121.583712],[31.221217,121.583682],[31.221243,121.583917],[31.220529,121.583302],[31.220821,121.582862],[31.220867,121.582437],[31.221094,121.582248],[31.221444,121.582566]]";
        path = path.replace("[", "").replace("]", "").replace("\n", "").trim();
        String[] split = path.split(",");
        String[] doubles = new String[split.length];
        int idx = 0;
        for (int i = 0; i < split.length; i += 2) {
            double[] res = GPSUtil.gcj02_To_Gps84(Double.parseDouble(split[i]), Double.parseDouble(split[i + 1]));
            doubles[idx++] = res[0] + "";
            doubles[idx++] = res[1] + "";
        }
        split = doubles;
        HashSet<String> set = new HashSet<>();
        // 地图缩放级别
        int zoom = 18;

        List<GeoPoint> list = new ArrayList<>();
        for (int i = 0; i < split.length; i += 2) {
            int[] ints = FourBoundariesGraphUtil.calculateTileXY(Double.parseDouble(split[i])
                    , Double.parseDouble(split[i + 1]), zoom);
            set.add(ints[0] + "/" + ints[1]);
            list.add(new GeoPoint(Double.parseDouble(split[i + 1]), Double.parseDouble(split[i])));
        }
        List<Double> xlist = list.stream().map(GeoPoint::getX).collect(Collectors.toList());
        List<Double> ylist = list.stream().map(GeoPoint::getY).collect(Collectors.toList());
        double[] xMinMax = FourBoundariesGraphUtil.findMinMax(xlist);
        double[] yMinMax = FourBoundariesGraphUtil.findMinMax(ylist);
        double[] rect_pts = new double[]{xMinMax[0], yMinMax[1], xMinMax[1], yMinMax[0]};


        String downloadPicturePath = "D:/tmp/pic/";
        Content content = downloadPic(rect_pts, zoom, downloadPicturePath);
        BoundingBox boundingBox = new BoundingBox();

        getBoundingBox(set, zoom, boundingBox);

        System.out.println("四至节点：" + Arrays.toString(rect_pts));
        System.out.println("瓦片表示范围：" +  boundingBox.toString());



        List<BufferedImage> tiles = new ArrayList<>();
        for (File file : content.getAllImg()) {
            try {
                tiles.add(ImageIO.read(file));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        String originImagePath = "D:/merged_map融合原图.png";
        try {
            mergeTiles(tiles, originImagePath, content.getWidth(), content.getHeight());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<Integer> polygonSingle = getPolygonSingle(list, boundingBox, content, zoom);
        int[] xArr = new int[polygonSingle.size() / 2], yArr = new int[polygonSingle.size() / 2];
        int j = 0, k = 0;
        for (int i = 0; i < polygonSingle.size(); i++) {
            if ((i % 2) == 0) {
                xArr[j++] = polygonSingle.get(i);
            } else {
                yArr[k++] = polygonSingle.get(i);
            }
        }

        ArrayList<GeoPoint> siZiPoints = new ArrayList<>();
        siZiPoints.add(new GeoPoint(xMinMax[0], yMinMax[1]));
        siZiPoints.add(new GeoPoint(xMinMax[1], yMinMax[0]));
        List<Integer> siZi = getPolygonSingle(siZiPoints, boundingBox, content, zoom);

        try {
            Image src = Toolkit.getDefaultToolkit().getImage(originImagePath);
            BufferedImage image = BufferedImageBuilder.toBufferedImage(src);
            Graphics2D g = (Graphics2D) image.getGraphics();

            drawLines(g, xArr, yArr, polygonSingle, siZi);


            Font font = new Font("宋体", Font.BOLD, 20);
            g.setFont(font);
            g.setColor(Color.YELLOW);


            g.drawString("经度:" + LatLngUtil.latLng2Dfm(xMinMax[0]), siZi.get(0) - 200, siZi.get(1) - 50);
            g.drawString("纬度:" + LatLngUtil.latLng2Dfm(yMinMax[1]), siZi.get(0) - 200, siZi.get(1) - 30);
            g.drawString("西北角", siZi.get(0) - 200, siZi.get(1) - 10);

            g.drawString("经度:" + LatLngUtil.latLng2Dfm(xMinMax[1]), siZi.get(2) - 50, siZi.get(1) - 50);
            g.drawString("纬度:" + LatLngUtil.latLng2Dfm(yMinMax[1]), siZi.get(2) - 50, siZi.get(1) - 30);
            g.drawString("东北角", siZi.get(2) - 50, siZi.get(1) - 10);

            g.drawString("经度:" + LatLngUtil.latLng2Dfm(xMinMax[0]), siZi.get(0) - 200, siZi.get(3) + 60); // 绘制文本
            g.drawString("纬度:" + LatLngUtil.latLng2Dfm(yMinMax[0]), siZi.get(0) - 200, siZi.get(3) + 40); // 绘制文本
            g.drawString("西南角", siZi.get(0) - 200, siZi.get(3) + 20);

            g.drawString("经度:" + LatLngUtil.latLng2Dfm(xMinMax[1]), siZi.get(2) - 50, siZi.get(3) + 60); // 绘制文本
            g.drawString("纬度:" + LatLngUtil.latLng2Dfm(yMinMax[0]), siZi.get(2) - 50, siZi.get(3) + 40); // 绘制文本
            g.drawString("东南角", siZi.get(2) - 50, siZi.get(3) + 20);

            font = new Font("宋体", Font.BOLD, 20);
            g.setFont(font);
            g.setColor(Color.RED);
            g.drawString("创建时间:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), 256 * content.width / 2 - 160, 256 * content.height - 5);

            String dkid = "4300000000000";
            String area = "11.9亩";
            g.drawString(dkid + " " + area, ((siZi.get(0) + siZi.get(2)) / 2) - 100, siZi.get(1) - 80);

            FileOutputStream out = new FileOutputStream("D:/merged_ploygon_map融合图.png");


            ImageIO.write(image, "png", out);

            String cutPicturePath = "D:/merged_ploygon_map_sub融合子图.png";
            FileOutputStream out2 = new FileOutputStream(cutPicturePath);
            BufferedImage subImage = image.getSubimage(siZi.get(0) - 200, siZi.get(1) - 100, siZi.get(2) - siZi.get(0) + 400, siZi.get(3) - siZi.get(1) + 200);
            Graphics2D g2 = (Graphics2D) image.getGraphics();
            font = new Font("宋体", Font.BOLD, 20);
            g2.setFont(font);
            g2.setColor(Color.RED);
            g2.drawString("创建时间:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), siZi.get(0) - 100 + (siZi.get(2) - siZi.get(0) + 210) / 2 - 150,
                    siZi.get(1) - 100 + siZi.get(3) - siZi.get(1) + 200 - 10);
            ImageIO.write(subImage, "png", out2);
            double scaleX = 830d / (siZi.get(2) - siZi.get(0) + 210);

            String thumbnailPicturePath = "D:/merged_ploygon_map_sub_thumbnail小图.png";
            enlargementImageByRatio(cutPicturePath, thumbnailPicturePath,
                    scaleX, scaleX);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("Tiles merged successfully!");
    }
    private static void drawLines(Graphics2D g, int[] xArr, int[] yArr, List<Integer> polygonSingle, List<Integer> siZi) {
        g.setColor(Color.BLUE);
        g.setStroke(new BasicStroke(2.0f));
        g.drawPolygon(xArr, yArr, polygonSingle.size() / 2);

        BasicStroke bs = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{10, 10}, 0);
        g.setStroke(bs);
        g.setColor(Color.YELLOW);
        g.drawRect(siZi.get(0), siZi.get(1), Math.abs(siZi.get(2) - siZi.get(0)), Math.abs(siZi.get(3) - siZi.get(1)));
    }
    private static BufferedImage downloadTileImage(String tileUrl) throws IOException {
        URL url = new URL(tileUrl);
        return ImageIO.read(url);
    }

    public static void mergeTiles(List<BufferedImage> tiles, String outputImagePath, int widthCnt, int heightCnt) throws IOException {
        // 假设所有瓦片都是正方形，获取瓦片的宽度和高度
        int tileWidth = tiles.get(0).getWidth();
        int tileHeight = tiles.get(0).getHeight();

        // 计算合并后图像的尺寸
        int width = tileWidth * widthCnt;// (int) Math.ceil(Math.sqrt(tiles.size())) * tileWidth;
        int height = tileHeight * heightCnt;// (int) Math.ceil(Math.sqrt(tiles.size())) * tileHeight;// width; //
        // 假设合并后的地图是正方形

        // 创建一个新的图像，用于合并后的地图
        BufferedImage mergedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 使用Graphics2D来绘制图像
        Graphics2D g2d = mergedImage.createGraphics();

        // 绘制瓦片到新图像上
        int x = 0;
        int y = 0;
        for (BufferedImage tile : tiles) {
            g2d.drawImage(tile, x, y, null);
            x += tileWidth;
            if (x >= width) {
                x = 0;
                y += tileHeight;
            }
        }

        // 释放Graphics2D资源
        g2d.dispose();

        // 将合并后的图像写入文件
        ImageIO.write(mergedImage, "PNG", new File(outputImagePath));
    }

    private static void mergePic(String path, String outputImagePath) {
        try {
            // 示例：从网络下载四个瓦片图片
            double[] rect_pts = new double[]{121.27d, 31.4d, 121.75d, 31.0d};
            Content content = downloadPic(rect_pts, 15, "C:\\Users\\yangzp\\Pictures\\pic_coll\\");
            List<BufferedImage> tiles = new ArrayList<>();
            for (File tileUrl : content.getAllImg()) {
                tiles.add(ImageIO.read(tileUrl));
            }


            mergeTiles(tiles, outputImagePath, content.getWidth(), content.getHeight());
            System.out.println("Tiles merged successfully!");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Error merging tiles: " + e.getMessage());
        }
    }

    public static void enlargementImageByRatio(String srcImagePath, String toImagePath, double widthRatio, double heightRatio) throws IOException {
        try {

            File file = new File(srcImagePath);
            BufferedImage src = ImageIO.read(file);
            int width = src.getWidth();
            int height = src.getHeight();

            BufferedImage tag = new BufferedImage((int) (width * widthRatio), (int) (height * heightRatio), BufferedImage.TYPE_INT_RGB);

            tag.getGraphics().drawImage(src, 0, 0, (int) (width * widthRatio), (int) (height * heightRatio), null);

            ImageIO.write(tag, "jpeg", new File(toImagePath));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void getBoundingBox(HashSet<String> set, int zoom, BoundingBox boundingBox) {
        for (String s : set) {
            String[] xy = s.split("/");
            BoundingBox boundingBoxTmp = FourBoundariesGraphUtil.tile2boundingBox(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]), zoom);
            if (boundingBox.south == 0d) {
                boundingBox.south = boundingBoxTmp.south;
            }
            if (boundingBox.west == 0d) {
                boundingBox.west = boundingBoxTmp.west;
            }
            if (boundingBox.north == 0d) {
                boundingBox.north = boundingBoxTmp.north;
            }
            if (boundingBox.east == 0d) {
                boundingBox.east = boundingBoxTmp.east;
            }

            boundingBox.south = Math.min(boundingBoxTmp.south, boundingBox.south);
            boundingBox.east = Math.max(boundingBoxTmp.east, boundingBox.east);
            boundingBox.north = Math.max(boundingBoxTmp.north, boundingBox.north);
            boundingBox.west = Math.min(boundingBoxTmp.west, boundingBox.west);
        }
    }

    private static List<Integer> getPolygonSingle(List<GeoPoint> list, BoundingBox boundingBox, Content content, int zoom) {
        String originXy = content.getOriginXy();
        int originX = Integer.parseInt(originXy.split(":")[0]);
        int originY = Integer.parseInt(originXy.split(":")[1]);
        List<Integer> res = new ArrayList<>();
        for (GeoPoint point : list) {
            int[] pointXy = FourBoundariesGraphUtil.calculateTileXY(point.getY(), point.getX(), zoom);
            BoundingBox tmp = FourBoundariesGraphUtil.tile2boundingBox(pointXy[0], pointXy[1], zoom);
            res.add((pointXy[0] - originX) * 256 + (int) ((point.getX() - tmp.west) / (tmp.east - tmp.west) * 256));
            res.add((pointXy[1] - originY) * 256 + (int) ((tmp.north - point.getY()) / (tmp.north - tmp.south) * 256));
        }
        res.add(res.get(0));
        res.add(res.get(1));
        return res;
    }

    public static Content downloadPic(double[] rect_pts, int zoom, String pathParent) {

        int[] leftUp = FourBoundariesGraphUtil.calculateTileXY(rect_pts[1], rect_pts[0], zoom);
        leftUp[0] -= 1;
        leftUp[1] -= 1;
        int[] rightDown = FourBoundariesGraphUtil.calculateTileXY(rect_pts[3], rect_pts[2], zoom);
        rightDown[0] += 1;
        rightDown[1] += 1;

        int yLen = rightDown[1] - leftUp[1];
        int xLen = rightDown[0] - leftUp[0];
        if (yLen != xLen) {
            if (yLen > xLen) {
                rightDown[0] += (yLen - xLen);
            } else {
                rightDown[1] += (xLen - yLen);
            }
        }

        pathParent += zoom + "/";
        List<File> allImg = new ArrayList<>();
        // 从左上角开始从左到右，从上到下依次生成图片，图片序号依次递增
        for (int j = leftUp[1]; j <= rightDown[1]; j++) {
            for (int i = leftUp[0]; i <= rightDown[0]; i++) {
                System.out.println("/" + j + "/" + i);
                String savePath = pathParent + "/" + j + "/" + i + ".png";
                if (!FileUtil.exist(savePath)) {
                    HttpOkUtil.downloadImg("http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile" + "&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=" + zoom + "&TILEROW=" + j + "&TILECOL=" + i + "&tk=ee5b1beee9ba49d8b620d88522f78fa1", savePath);
                }
                allImg.add(new File(savePath));
            }
        }
        return new Content(allImg, rightDown[0] - leftUp[0] + 1, rightDown[1] - leftUp[1] + 1, ("" + leftUp[0]) + ":" + leftUp[1]);
    }
}
